package com.jstyle.jclifexd.activity;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.v4.app.ActivityCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;


import com.amap.api.location.AMapLocation;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PolylineOptions;
import com.jstyle.blesdk.Util.ResolveUtil;
import com.jstyle.blesdk.cmdenum.SendCmdState;
import com.jstyle.blesdk.constant.DeviceConst;
import com.jstyle.blesdk.constant.DeviceKey;
import com.jstyle.blesdk.model.ExerciseMode;
import com.jstyle.jclifexd.NetWork.NetWorkUtil;
import com.jstyle.jclifexd.R;
import com.jstyle.jclifexd.ble.BleManager;
import com.jstyle.jclifexd.daoManager.GpsDataDaoManager;
import com.jstyle.jclifexd.daoManager.PathRecordDaoManager;
import com.jstyle.jclifexd.daoManager.UserInfoDaoManager;
import com.jstyle.jclifexd.model.GpsData;
import com.jstyle.jclifexd.model.PathRecord;
import com.jstyle.jclifexd.model.UserInfo;
import com.jstyle.jclifexd.utils.CoordinateUtil;
import com.jstyle.jclifexd.utils.DateUtil;
import com.jstyle.jclifexd.utils.ResolveData;
import com.jstyle.jclifexd.utils.SchedulersTransformer;
import com.jstyle.jclifexd.utils.SharedPreferenceUtils;
import com.jstyle.jclifexd.utils.Utils;
import com.jstyle.jclifexd.view.TrackStopView;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import butterknife.BindArray;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

import static com.jstyle.blesdk.cmdenum.SendCmdState.Set_EXERCISE_MODE;

public class TrackGoogleActivity extends BaseActivity implements SensorEventListener, OnMapReadyCallback, LocationSource {
    public final static String key_ExerciseMode = "key_ExerciseMode";

    @BindView(R.id.rl_bottom_sheet)
    LinearLayout rlBottomSheet;
    @BindView(R.id.CoordinatorLayout)
    android.support.design.widget.CoordinatorLayout CoordinatorLayout;
    @BindView(R.id.rL_bar)
    RelativeLayout rLBar;
    @BindView(R.id.iv_down)
    ImageView ivDown;
    @BindView(R.id.bt_exercise_time)
    Button btExerciseTime;
    @BindView(R.id.bt_exercise_cal)
    Button btExerciseCal;
    @BindView(R.id.bt_exercise_pace)
    Button btExercisePace;
    @BindView(R.id.bt_exercise_heart)
    Button btExerciseHeart;
    @BindView(R.id.tv_track_distacne)
    TextView tvTrackDistacne;
    @BindView(R.id.iv_gps_rssi)
    ImageView ivGpsRssi;
    @BindView(R.id.bt_gpsrssi)
    Button btGpsrssi;
    @BindView(R.id.iv_start_location)
    ImageView ivStartLocation;
    @BindArray(R.array.heartRange_array)
    String[] heartArray;
    @BindView(R.id.iv_finish)
    TrackStopView ivFinish;
    @BindView(R.id.ll_track_run_0)
    LinearLayout llTrackRun0;
    @BindView(R.id.ll_track_run_1)
    LinearLayout llTrackRun1;
    @BindView(R.id.bt_exercise_step)
    Button btExerciseStep;
    private PathRecord pathRecord;
    private BottomSheetBehavior<LinearLayout> behavior;
    private boolean enable;
    private Disposable disposable;
    private int countTime;
    private NumberFormat numberFormat;
    private int lastTotalSteps;
    private int position;
    private List<Float> paceStringList = new ArrayList<>();
    int heartColor = Color.parseColor("#6C6C6C");
    int hintColor = Color.parseColor("#6C6C6C");
    private float pace;
    private int MHR;
    private FusedLocationProviderClient fusedLocationClient;
    private LocationRequest locationRequest;
    private LocationCallback locationCallback;
    int oldStep = 0;
    float oldCal;
    float oldDistance;
    List<Integer> stepList = new ArrayList<>();
    List<Integer> heartList = new ArrayList<>();
    private int activityStep;
    private float activityCal;
    private float activityDistance;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track_google);
        ButterKnife.bind(this);
        setHiddenBack(true);
        SupportMapFragment mapFragment =
                (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapTrack);
        mapFragment.getMapAsync(this);
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        locationRequest = new LocationRequest()
                .setInterval(1000).setFastestInterval(500)
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        stepList.clear();
        heartList.clear();
         oldStep = 0;
         oldCal= 0;
         oldDistance= 0;
        countTime=0;

        init();
    }

    private void saveExerciseMode() {
        pathRecord.setCalString(numberFormat.format(activityCal));
        pathRecord.setMDistance(numberFormat.format(activityDistance));
        pathRecord.setMAveragespeed(getPace());
        pathRecord.setHeart(GetAvgHeart());
        pathRecord.setMStep(String.valueOf(activityStep));
        pathRecord.setMDuration(String.valueOf(countTime));
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                PathRecordDaoManager.insertPathRecord(pathRecord);
                e.onComplete();
            }
        }).compose(SchedulersTransformer.<String>applySchedulers()).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.i(TAG, "onSubscribe: ");
            }

            @Override
            public void onNext(String value) {
                Log.i(TAG, "onNext: ");
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: mode" + e.getMessage());
            }

            @Override
            public void onComplete() {

            }
        });
    }


    private String GetAvgHeart() {
        int total = 0;
        int size = heartList.size();
        for (int i = 0; i < size; i++) {
            total += heartList.get(i);
        }
        return total == 0 ? String.valueOf(0) : total / size + "";
    }

    private String getPace() {

        int paceSecond = (int) (countTime / activityDistance);
        int speedMin = paceSecond / 60;
        int speedS = paceSecond % 60;
        return String.format("%02d", speedMin) + "'" + String.format("%02d", speedS) + "\"";
    }
    private void handleLocation(Location location) {
        Log.i(TAG, "handleLocation: ");
        if (googleMap == null) return;

        LatLng latLng = CoordinateUtil.transformFromWGSToGCJGoogle(location.getLatitude(), location.getLongitude(), false);
        location.setLatitude(latLng.latitude);
        location.setLongitude(latLng.longitude);
        if (onLocationChangedListener != null)
            onLocationChangedListener.onLocationChanged(location);
        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17f));
        reDrawLine(latLng);
        updatePace(location.getSpeed());
        pathRecord.addPoint(new AMapLocation(location));
    }

    private void updatePace(float speed) {
        if (speed > 0.5f) {
            pace = 1000f / speed;
            String paceString = ResolveData.getShowPace(this, DateUtil.getPaceTime((int) pace)) + "\n " + ResolveData.getPaceLabel(this);
            btExercisePace.setText(paceString);
        }
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
    }

    private static final String TAG = "TrackGoogleActivity";
    int lastTop = 0;


    private void init() {
        ivFinish.setOnStopListener(new TrackStopView.onLongClickListener() {
            @Override
            public void finish() {
                if(countTime>=180){
                    saveExerciseMode();
                    saveRecord(pathRecord.getmPathLinePoints(), pathRecord.getMDate());
                    saveData();
                }else{
                    TrackGoogleActivity.this.finish();
                }
            }

            @Override
            public void onClick() {

            }
        });
        getMaxHr();
        position = getIntent().getIntExtra(TrackGoogleActivity.key_ExerciseMode, 0);
        // initSensor();
        if (position == ExerciseMode.Mode_RUN) {
            llTrackRun0.setVisibility(View.VISIBLE);
            llTrackRun1.setVisibility(View.VISIBLE);
        } else if (position == ExerciseMode.Mode_CLIMB) {
            llTrackRun0.setVisibility(View.GONE);
            llTrackRun1.setVisibility(View.GONE);
        } else {
            llTrackRun0.setVisibility(View.GONE);
            llTrackRun1.setVisibility(View.GONE);

        }
        numberFormat = NumberFormat.getNumberInstance();
        numberFormat.setGroupingUsed(false);
        numberFormat.setMaximumFractionDigits(2);

        String address = SharedPreferenceUtils.getSpString(SharedPreferenceUtils.KEY_ADDRESS);
        pathRecord = new PathRecord();
        pathRecord.setMDate(DateUtil.getFormatTimeString(new Date().getTime()));
        pathRecord.setExerciseMode(0);
        pathRecord.setAddress(address);
        gpsData = new GpsData();
        gpsData.setDate(DateUtil.getFormatTimeString(new Date().getTime()));

        startCount();
        behavior = BottomSheetBehavior.from(rlBottomSheet);
        behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
                    ivDown.setRotation(180);
                } else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                    ivDown.setRotation(0);
                }
                Log.i(TAG, "onStateChanged: ");
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

                rLBar.setTranslationY(-(bottomSheet.getHeight() - behavior.getPeekHeight()) * slideOffset);
                lastTop = bottomSheet.getTop();
            }
        });
        ivDown.postDelayed(new Runnable() {
            @Override
            public void run() {
                behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        }, 50);
        ivDown.setRotation(0);
        initView();
        ivGpsRssi.setImageLevel(2);
    }

    private void saveData() {
        finish();
    }
    GpsData gpsData;
    protected void saveRecord(List<AMapLocation> list, String time) {
        String address = SharedPreferenceUtils.getSpString(SharedPreferenceUtils.KEY_ADDRESS);
        if (TextUtils.isEmpty(address)) return;
        if (list != null && list.size() > 0) {
            String pathlineSring = getPathLineString(list);
            gpsData.setPathLineString(pathlineSring);
            gpsData.setAddress(address);
            GpsDataDaoManager.insertPathRecord(gpsData);
        } else {

        }
    }


    private void initView() {
        tvTrackDistacne.setText(ResolveData.getShowDistance(String.valueOf(0 / 1000f)) + ResolveData.getDistanceLabel());
        String paceString = ResolveData.getShowPace(this, DateUtil.getPaceTime(0)) + "\n " + ResolveData.getPaceLabel(this);
        btExercisePace.setText(paceString);

    }


    @Override
    public void onResume() {
        super.onResume();

    }

    @Override
    public void onPause() {
        super.onPause();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

       /* startExercise(ExerciseMode.Status_FINISH);*/
        unSubscribe(disposable);
        ExerciseMode exerciseMode = new ExerciseMode();
        exerciseMode.setEnableStatus( ExerciseMode.Status_FINISH);
        sendData(Set_EXERCISE_MODE, exerciseMode);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

    }


    float distance = 0;
    int gpsRssi;
    float indexDistance = 1000;//每1km记录一次配速
    float indexPaceTime = 0;//每1km耗费的时间

    List<LatLng> mOriginLatLngList = new ArrayList<>();
    LatLng lastLng;

    private void reDrawLine(LatLng latLng) {
        mOriginLatLngList.add(latLng);
        googleMap.addPolyline(new PolylineOptions()
                .color(Color.GREEN)
                .clickable(true)
                .addAll(mOriginLatLngList));
       // updateDistance(latLng);
        lastLng = latLng;
    }



    private void getMaxHr() {
        String account = NetWorkUtil.getUserId();
        UserInfo userInfo = UserInfoDaoManager.getUserByUid(account);
        if (userInfo == null) {
            userInfo = new UserInfo();
            userInfo.setUserId(account);
            UserInfoDaoManager.insertUser(userInfo);
        }
        String birthday = userInfo.getBirthday();
        int userYear = Integer.parseInt(birthday.split("-")[0]);
        Calendar calendar = Calendar.getInstance();
        int age = calendar.get(Calendar.YEAR) - userYear;
        MHR = 220 - age;
    }


    @OnClick({R.id.iv_down,R.id.iv_start_location})
    public void onViewClicked(View view) {
        if(Utils.isFastClick()){return;}
        switch (view.getId()) {
            case R.id.iv_down:
                if (behavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    ivDown.setRotation(0);
                } else if (behavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
                    behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    ivDown.setRotation(180);
                }
                break;
            case R.id.iv_start_location:
                startLocation();
                break;
        }
    }

    private void startExercise(int status) {

        ExerciseMode exerciseMode = new ExerciseMode();
        exerciseMode.setEnableStatus(status);
        exerciseMode.setExerciseMode(exerciseMode.getExerciseMode(position));
        offerData(SendCmdState.Set_EXERCISE_MODE, exerciseMode);
        offerData();
    }

    public void startCount() {
        enable = !enable;
        int status = 0;
        if (enable) {
            status = countTime == 0 ? ExerciseMode.Status_START : ExerciseMode.Status_CONTUINE;
        } else {
            status = ExerciseMode.Status_PAUSE;
        }
        startExercise(status);
        //ivStart.setImageResource(enable ? R.drawable.exercise_pause : R.drawable.exercise_start);

        if (enable) {
            Observable.interval(0, 1, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Long>() {
                @Override
                public void onSubscribe(Disposable d) {
                    disposable = d;
                }

                @Override
                public void onNext(Long value) {
                    countTime++;
                    if (countTime != 0 && countTime % 5 == 0) {//5秒添加一次步数
                        if (stepList.size() == 0) {
                            stepList.add(step);
                        } else {
                            float lastStep = stepList.get(stepList.size() - 1);
                            lastTotalSteps += lastStep;
                            Log.i(TAG, "onNext: " + lastStep + " " + step + " " + (step - lastTotalSteps));
                            stepList.add(step - lastTotalSteps);
                        }
                    }
                    String time = DateUtil.getActivityTime(countTime);
                    btExerciseTime.setText(time);
                    sendHeartPackage(distance / 1000f, (int) pace, gpsRssi);
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });
        } else {
            disposable.dispose();
        }

    }


    private String amapLocationToString(AMapLocation location) {
        StringBuffer locString = new StringBuffer();
        locString.append(location.getLatitude()).append(",");
        locString.append(location.getLongitude());

        return locString.toString();
    }

    private String getPathListString(List<Float> list) {
        if (list == null || list.size() == 0) {
            return "";
        }
        StringBuffer pathline = new StringBuffer();
        for (float value : list) {
            pathline.append(String.valueOf(value)).append(",");
        }
        String pathLineString = pathline.toString();
        pathLineString = pathLineString.substring(0,
                pathLineString.length() - 1);
        return pathLineString;
    }




    private String getPathLineString(List<AMapLocation> list) {
        if (list == null || list.size() == 0) {
            return "";
        }
        StringBuffer pathline = new StringBuffer();
        for (int i = 0; i < list.size(); i++) {
            AMapLocation location = list.get(i);
            String locString = amapLocationToString(location);
            pathline.append(locString).append(";");
        }
        String pathLineString = pathline.toString();
        pathLineString = pathLineString.substring(0,
                pathLineString.length() - 1);
        return pathLineString;
    }





    private Spannable getKcalSpannable(String text) {
        String startText = getString(R.string.cal_laber);
        int start = text.indexOf(startText);
        int end = start + startText.length();
        Spannable kcalSpannable = new SpannableString(text);
        setColorSpannable(kcalSpannable, start, end, hintColor);
        return kcalSpannable;
    }



    private Spannable getHeartSpannable(String text, String label) {

        String startText = label;
        String startText2 = getString(R.string.hr_laber);
        int start = text.indexOf(startText);
        int end = start + startText.length();
        int start2 = text.indexOf(startText2);
        int end2 = start2 + startText2.length();
        Spannable kcalSpannable = new SpannableString(text);
        setColorSpannable(kcalSpannable, start, end, heartColor);
        setColorSpannable(kcalSpannable, start2, end2, hintColor);
        return kcalSpannable;
    }



    private void setColorSpannable(Spannable word, int start, int end, int textColor) {
        word.setSpan(new ForegroundColorSpan(textColor), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
    }

    @Override
    public void dataCallback(Map<String, String> maps, SendCmdState sendCmdState) {
        super.dataCallback(maps, sendCmdState);
        switch (sendCmdState) {
            case SET_STEP_MODEL:
                final String heart = maps.get(DeviceKey.KHeartValue);
                final String cal = maps.get(DeviceKey.KCalories);
                int deviceStep = Integer.valueOf(maps.get(DeviceKey.KTotalSteps));
                float deviceDistance = Float.valueOf(maps.get(DeviceKey.KDistance));
                float deviceCal = Float.valueOf(cal);
                if (oldStep == 0 && deviceStep != 0) {
                    oldStep = deviceStep;
                }
                activityStep = deviceStep - oldStep;
                if (oldCal == 0 && deviceCal != 0) {
                    oldCal = deviceCal;
                }
                activityCal = deviceCal - oldCal;
                if (oldDistance == 0 && deviceDistance != 0) {
                    oldDistance = deviceDistance;
                }
                activityDistance = deviceDistance - oldDistance;
                String showDistance = numberFormat.format(activityDistance);
                String showCal = activityCal < 0 ? "0.0" : numberFormat.format(activityCal);
                String hrLabel = " " + getString(R.string.hr_laber);
                heartList.add(Integer.valueOf(heart));
                int heartLevel = ResolveData.getHeartRange(Float.valueOf(heart), MHR);
                if (heartLevel == -1) heartLevel = 0;
                String heartLabel = heartArray[heartLevel];
                tvTrackDistacne.setText(ResolveData.getShowDistance(showDistance) + ResolveData.getDistanceLabel());
                btExerciseStep.setText(String.valueOf(activityStep));
                btExerciseHeart.setText(getHeartSpannable(heart + hrLabel + " \n " + heartLabel, heartLabel));
                btExerciseCal.setText(getKcalSpannable(showCal + " \n " + getString(R.string.cal_laber)));
        }
    }

    int step = 0;

    @Override
    public void onSensorChanged(SensorEvent event) {
//        if (mSteps != 0) {
//            step += event.values[0] - mSteps;
//        }
//        mSteps = event.values[0];

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    private void sendHeartPackage(float distance, int space, int rssi) {
        byte[] value = new byte[16];
        byte[] distanceValue = getByteArray(distance);
        int min = space / 60;
        int second = space % 60;
        Log.i(TAG, "sendHeartPackage: " + distance);
        value[0] = DeviceConst.CMD_heart_package;
        System.arraycopy(distanceValue, 0, value, 1, distanceValue.length);
        value[5] = (byte) min;
        value[6] = (byte) second;
        value[7] = (byte) rssi;
        ResolveUtil.crcValue(value);
        BleManager.getInstance().writeValue(value);
    }

    public byte[] getByteArray(float f) {
        int intbits = Float.floatToIntBits(f);//将float里面的二进制串解释为int整数
        return getByteArray(intbits);
    }

    public static byte[] getByteArray(int i) {
        byte[] b = new byte[4];
        b[3] = (byte) ((i & 0xff000000) >> 24);
        b[2] = (byte) ((i & 0x00ff0000) >> 16);
        b[1] = (byte) ((i & 0x0000ff00) >> 8);
        b[0] = (byte) (i & 0x000000ff);
        return b;
    }

    GoogleMap googleMap;
    OnLocationChangedListener onLocationChangedListener;

    @Override
    public void onMapReady(GoogleMap googleMap) {
        this.googleMap = googleMap;

        startLocation();
        Log.i(TAG, "onMapReady: ");
    }

    private void startLocation() {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            return;
        }
         locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                handleLocation(locationResult.getLastLocation());
            }
        };
        googleMap.setLocationSource(this);
        googleMap.setMyLocationEnabled(true);
        UiSettings mUiSettings = googleMap.getUiSettings();
        mUiSettings.setZoomControlsEnabled(false);
        mUiSettings.setCompassEnabled(false);
        mUiSettings.setMyLocationButtonEnabled(false);
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
    }

    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        Log.i(TAG, "activate: ");
        this.onLocationChangedListener = onLocationChangedListener;


    }

    @Override
    public void deactivate() {
        Log.i(TAG, "deactivate: ");
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }
}
